package com.dubbo.ratelimit.limit;

import com.google.common.util.concurrent.RateLimiter;

import java.io.IOException;
import java.util.concurrent.CountDownLatch;

/**
 * 限流：令牌桶、漏桶
 * 每个API接口都是有访问上限的，通常的策略就是拒绝多余的访问,或者让多余的访问排队等待服务,或者引流
 * Google开源工具包Guava提供了限流工具类RateLimiter,该类基于令牌桶算法(Token Bucket)来完成限流
 * 一种是如果拿不到立刻返回false,一种会阻塞等待一段时间看能不能拿到
 */
public class Token {

    //bursty(令牌桶) 每秒1000个令牌的RateLimiter
    private RateLimiter rateLimiter = RateLimiter.create(1000); //qps是1000

    /*// 漏桶
    RateLimiter rateLimiter1=RateLimiter.create(1000,10,TimeUnit.MILLISECONDS);*/

    private void doPay() {
        // 1、阻塞  rateLimiter.acquire();
        // 2、立即返回 tryAcquire() 未请求到limiter则立即返回false
        if (rateLimiter.tryAcquire()) {
            //尝试去获取一个令牌，立即返回
            System.out.println(Thread.currentThread().getName() + "开始执行支付");
        } else {
            System.out.println("系统繁忙");
        }
    }

    public static void main(String[] args) throws IOException {
        Token token = new Token();
        CountDownLatch countDownLatch = new CountDownLatch(1);
        for (int i = 0; i < 1000; i++) {
            new Thread(() -> {
                try {
                    countDownLatch.await(); //使得当前线程阻塞
//                    Thread.sleep(random.nextInt(1000));
                    token.doPay();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }).start();
        }
        countDownLatch.countDown();
    }
}
